﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Jage.Data;
using Jage.GameEditor.Controls.Sprites;
using Jage.Win32;

namespace Jage.GameEditor.Controls.Animations
{
    public partial class AnimationEditor : UserControl
    {

        private readonly ListViewDatabinder<Data.Animation> _animationDatabinder;
        private readonly ListViewDatabinder<Data.Custom.AnimationSpriteForList> _animationSpritesDatabinder;

        public AnimationEditor()
        {
            InitializeComponent();
            _animationDatabinder = new ListViewDatabinder<Data.Animation>(listViewAnimations, "AnimationId");
            _animationDatabinder.AddColumnDefinition("Name");

            _animationSpritesDatabinder = new ListViewDatabinder<Data.Custom.AnimationSpriteForList>(listViewSprites, "AnimationSpriteId");
            _animationSpritesDatabinder.AddColumnDefinition("SequenceNumber");
            _animationSpritesDatabinder.AddColumnDefinition("SpritesheetName");
            _animationSpritesDatabinder.AddColumnDefinition("SpriteSortIndex");

            ComboBoxDirection.SelectedIndex = 0;
        }

        #region Methods

        #region Animations

        private void RefreshAnimations()
        {
            _animationDatabinder.Databind(Data.JageDb.Default.Animations.OrderBy(a => a.Name));
        }

        #endregion

        #region Animation Details

        private void RefreshAnimationSprites()
        {
            if (listViewAnimations.SelectedItems.Count > 0)
            {
                var animationId = _animationDatabinder.SelectedIds.First();
                var direction = int.Parse(ComboBoxDirection.SelectedItem as string);
                _animationSpritesDatabinder.Databind(from s in Data.JageDb.Default.AnimationSprites
                                                     where s.AnimationId == animationId && s.Direction == direction
                                                     orderby s.SequenceNumber
                                                     select
                                                         new Data.Custom.AnimationSpriteForList()
                                                             {
                                                                 SequenceNumber = s.SequenceNumber,
                                                                 AnimationSpriteId = s.AnimationSpriteId,
                                                                 SpritesheetName = s.Sprite.Spritesheet.Name,
                                                                 SpriteSortIndex = s.Sprite.SortIndex,
                                                                 Sprite = s.Sprite
                                                             });
            }
            else
            {
                _animationSpritesDatabinder.Clear();
            }
        }

        private void AddAnimationSprites(IEnumerable<Data.Sprite> sprites, Guid animationId)
        {
            var direction = int.Parse(ComboBoxDirection.SelectedItem as string);
            var sequenceNumberOrNull = (from s in Data.JageDb.Default.AnimationSprites where s.AnimationId == animationId && s.Direction == direction select s).Max(s => (int?)s.SequenceNumber);
            var sequenceNumber = sequenceNumberOrNull.GetValueOrDefault();
            foreach (var sprite in sprites)
            {
                Data.JageDb.Default.AnimationSprites.AddObject(Logic.Crud.AnimationSprite.GetNew(animationId, int.Parse(ComboBoxDirection.SelectedItem as string), sprite.SpriteId, ++sequenceNumber));
            }
            Data.JageDb.Default.SaveChanges();
            RefreshAnimationSprites();
        }

        private void CleanSequenceNumbers()
        {
            if (listViewAnimations.SelectedItems.Count > 0)
            {
                var animationId = _animationDatabinder.SelectedIds.First();
                int number = 1;
                foreach (var sprite in (from s in Data.JageDb.Default.AnimationSprites where s.AnimationId == animationId orderby s.SequenceNumber select s))
                {
                    if (sprite.SequenceNumber != number) sprite.SequenceNumber = number;
                    number++;
                }
                Data.JageDb.Default.SaveChanges();
            }
        }


        #endregion

        #endregion

        #region Events

        private void AnimationEditor_Load(object sender, EventArgs e)
        {
            RefreshAnimations();
        }

        #region Animations

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            string animationName;
            if (InputBox.ShowDialog("Add an animation", "Enter a name for the new animation:", out animationName) == DialogResult.OK)
            {
                var context = Data.JageDb.Default;
                context.Animations.AddObject(Logic.Crud.Animation.GetNew(animationName));
                context.SaveChanges();
                RefreshAnimations();
            }
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            if (listViewAnimations.SelectedItems.Count > 0)
            {
                if (MessageBox.Show(string.Format("Delete {0} animations?", listViewAnimations.SelectedItems.Count), "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    foreach (var animation in _animationDatabinder.SelectedObjects)
                    {
                        var animation1 = animation;
                        foreach (var animationSprite in from a in JageDb.Default.AnimationSprites where a.AnimationId == animation1.AnimationId select a)
                        {
                            JageDb.Default.AnimationSprites.DeleteObject(animationSprite);
                        }
                        JageDb.Default.Animations.DeleteObject(animation);
                    }
                    JageDb.Default.SaveChanges();
                    RefreshAnimations();
                    RefreshAnimationSprites();
                }
            }
        }

        private void listViewAnimations_SelectedIndexChanged(object sender, EventArgs e)
        {
            panel2.Enabled = listViewAnimations.SelectedItems.Count > 0;
            RefreshAnimationSprites();
        }

        private void listViewAnimations_DoubleClick(object sender, EventArgs e)
        {
            if (_animationDatabinder.SelectedObjects.Count() > 0)
            {
                string newName;
                var selectedAnimation = _animationDatabinder.SelectedObjects.First();
                if (InputBox.ShowDialog("Rename", "Enter a new name for the animation", selectedAnimation.Name, out newName,
                                    n => (from anim in JageDb.Default.Animations
                                          where anim.Name == n && anim.AnimationId != selectedAnimation.AnimationId
                                          select anim).Count() == 0, "Name must be unique") == DialogResult.OK)
                {
                    selectedAnimation.Name = newName;
                    JageDb.Default.SaveChanges();
                    RefreshAnimations();
                    RefreshAnimationSprites();
                }
            }
        }

        #endregion

        #region Animation Sprites

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            if (listViewAnimations.SelectedItems.Count > 0)
            {
                var browser = new SpriteBrowser();
                if (browser.ShowDialog() == DialogResult.OK)
                {
                    BusyBox.ShowBusy("Adding sprites...");
                    try
                    {
                        AddAnimationSprites(browser.SelectedSprites, _animationDatabinder.SelectedObjects.First().AnimationId);
                        RefreshAnimationSprites();
                    }
                    finally
                    {
                        BusyBox.HideBusy();
                    }
                }
            }
        }

        private void buttonDeleteSprites_Click(object sender, EventArgs e)
        {
            if (listViewSprites.SelectedItems.Count > 0 && MessageBox.Show(string.Format("Delete {0} sprites from the animation?", listViewSprites.SelectedItems.Count), "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                foreach (var sprite in Data.JageDb.Default.AnimationSprites.Where(s => _animationSpritesDatabinder.SelectedIds.Contains(s.AnimationSpriteId)))
                {
                    Data.JageDb.Default.AnimationSprites.DeleteObject(sprite);
                }
                Data.JageDb.Default.SaveChanges();
                CleanSequenceNumbers();
                RefreshAnimationSprites();
            }
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            // save selection of guids, because records will change listviewitems, selection must follow the records, not the listviewitems.
            var selection = _animationSpritesDatabinder.SelectedObjects;
            foreach (int index in listViewSprites.SelectedIndices)
            {
                SwitchSprites(index, index - 1);
            }
            _animationSpritesDatabinder.SelectedObjects = selection; // reapply original Guid selection
            Data.JageDb.Default.SaveChanges();
            RefreshAnimationSprites();
        }

        private void toolStripButton6_Click(object sender, EventArgs e)
        {
            // save selection of guids, because records will change listviewitems, selection must follow the records, not the listviewitems.
            var selection = _animationSpritesDatabinder.SelectedObjects;
            for (int i = listViewSprites.SelectedIndices.Count - 1; i >= 0; i--)
            {
                var index = listViewSprites.SelectedIndices[i];
                SwitchSprites(index, index + 1);
            }
            _animationSpritesDatabinder.SelectedObjects = selection; // reapply original Guid selection
            Data.JageDb.Default.SaveChanges();
            RefreshAnimationSprites();
        }

        private void SwitchSprites(int index1, int index2)
        {
            if (index1 >= 0 && index1 < listViewSprites.Items.Count && index2 >= 0 && index2 < listViewSprites.Items.Count)
            {
                var animationSprite1 = (Data.Custom.AnimationSpriteForList)listViewSprites.Items[index1].Tag;
                var animationSprite2 = (Data.Custom.AnimationSpriteForList)listViewSprites.Items[index2].Tag;
                var sprite1 = Data.JageDb.Default.AnimationSprites.Where(s => s.AnimationSpriteId == animationSprite1.AnimationSpriteId).Single();
                var sprite2 = Data.JageDb.Default.AnimationSprites.Where(s => s.AnimationSpriteId == animationSprite2.AnimationSpriteId).Single();

                // swap SortIndex
                int temp = sprite1.SequenceNumber;
                sprite1.SequenceNumber = sprite2.SequenceNumber;
                sprite2.SequenceNumber = temp;

                // swap places
                listViewSprites.Items[index1].Tag = animationSprite2;
                listViewSprites.Items[index2].Tag = animationSprite1;
            }
        }

        private void ComboBoxDirection_SelectedIndexChanged_1(object sender, EventArgs e)
        {
            RefreshAnimationSprites();
        }

        private void listViewSprites_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_animationSpritesDatabinder.SelectedIds.Count() > 0)
            {
                spritesheetSpritePreview1.SetResource(_animationSpritesDatabinder.SelectedObjects.First().Sprite);
            }
        }

        #endregion

        #endregion

    }
}
